/*
 * @Author: wuqingchun
 * @Date: 2024-04-15 15:28:50
 * @Description: 独占型智能指针
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-04-15 17:36:03
 */
#ifndef __MY_UNIQUE_PTR_H__
#define __MY_UNIQUE_PTR_H__

#include <functional>
#include <type_traits>

/// Primary template of default_delete, used by unique_ptr
template<typename _Tp>
struct my_default_delete
{
    /// Default constructor
    constexpr my_default_delete() noexcept = default;

    /** @brief Converting constructor.
     *
     * Allows conversion from a deleter for arrays of another type, @p _Up,
     * only if @p _Up* is convertible to @p _Tp*.
     */
    // template<typename _Up, typename = typename
    //     enable_if<is_convertible<_Up*, _Tp*>::value>::type>
    // my_default_delete(const my_default_delete<_Up>&) noexcept { }

    /// Calls @c delete @p __ptr
    void operator()(_Tp* __ptr) const
    {
        static_assert(!std::is_void<_Tp>::value, "can't delete pointer to incomplete type");
        static_assert(sizeof(_Tp)>0, "can't delete pointer to incomplete type");
        delete __ptr;
    }
};

template<typename T, typename DELETE_TYPE=my_default_delete<T>>
class my_unique_ptr
{
public:
    my_unique_ptr(T* pObjPtr)
    {
        m_pObjPtr = pObjPtr;
    }

    my_unique_ptr(T* pObjPtr, std::function<void(T*)> Deleter)
    {
        m_pObjPtr = pObjPtr;
        m_objDeleter = Deleter;
    }

    // 删除拷贝构造函数，禁止对象复制
    my_unique_ptr(const my_unique_ptr<T>& refUP) = delete;
    my_unique_ptr<T>& operator= (const my_unique_ptr<T>& refUP) = delete;

    // 移动构造函数
    my_unique_ptr(my_unique_ptr<T>&& refUP)
    {
        m_pObjPtr = refUP.m_pObjPtr;
        refUP.m_pObjPtr = nullptr;
    }

    ~my_unique_ptr()
    {
        if (m_pObjPtr != nullptr)
        {
            __CallDeleter();
        }
    }

    T& operator* ()
    {
        return *m_pObjPtr;
    }

    T* operator-> ()
    {
        return m_pObjPtr;
    }

    T& operator[] (size_t ulPos)
    {
        return m_pObjPtr[ulPos];
    }

    T* get()
    {
        return m_pObjPtr;
    }

    T* release()
    {
        T* __ptr = m_pObjPtr;
        m_pObjPtr = nullptr;

        return __ptr;
    }

    void reset()
    {
        if (m_pObjPtr != nullptr)
        {
            __CallDeleter();
        }
    }
    
private:
    void __CallDeleter()
    {
        if (m_objDeleter != nullptr)
        {
            m_objDeleter(m_pObjPtr);
        }
        else
        {
            DELETE_TYPE(m_pObjPtr);
        }

        m_pObjPtr = nullptr;
    }
private:
    T* m_pObjPtr {nullptr};

    std::function<void(T* pObjPtr)> m_objDeleter = nullptr;
};

#endif //__MY_UNIQUE_PTR_H__
